#pragma once

#include <string>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <memory>
#include <functional>

#include "Socket.hpp"
#include "NetCal.hpp"

using namespace socket_ns;

// 需要注意的是：TCP协议作为面向字节流，它是不具备区分报文的功能的
// 也就是说，当系统在应用层调用recv等函数将数据从传输层拿到应用层时，是有问题的
// 对于传输层：服务端OS接收到客户端的请求时，会将请求中的报头和报文分离，然后将报文放入缓冲区中，等待交给上层
// 但是TCP协议中，报头属性里没有指明报文长度的字段，这样一来，当上层从缓冲区中读取报文时，有可能会发送
// 这读取到了一个请求中一半的数据或者说把下一个请求中的数据也读取到了这样的事情。
// 那么这种事情是绝对不允许的，因此我们可以使用已有的协议或者是自定义协议来保证报文的完整性和独立性。

// 对于协议，当我们读取到了一个完整的(协议)请求时，我们需要对其中的各个字段进行分析和处理
// // 那就意味者我们需要有能够描述一个协议(请求)的对象，让后将字符串形式的请求转换成协议对象，这就是：反序列化
// // 同样的，当我们要发送一个(协议)请求时，我们需要构建出一个(协议)，那么我们就需要把一个对象转换成字符串，这就是：序列化
// 因为在网络传输中，由于各个主机的底层环境不同，我们不可能直接发送二进制数据给对方，对方主机很有可能无法解析这个数据(看不懂)
// 因此我们需要将这种数据用字符串(更上一层的)这种大家都能够理解的形式进行传递，然后序列化和反序列化。
// 这种协议，也就是应用层协议，而Tcp之类的协议则是传输层协议

// 对于序列化、反序列化 和 Json 
// 1. JsonCpp只是用来方便进行序列化和反序列化的工具，Json本身并不代表序列化
// 2. 序列化和反序列化最终是针对 请求 和 响应 的，而不是单独针对协议或者是请求任务。

// 接收请求->反序列化、处理协议->执行任务->构建应答、序列化->发送应答

using process_t = std::function<std::shared_ptr<Response>(std::shared_ptr<Request>)>;

class IOservice
{
public:
    IOservice(process_t process)
        :_process(process)
    {
    }

    void Service(SockPtr sockfd, InetAddr addr)
    {
        std::string packagestreamqueue;     //数据流队列，向这里面添加tcp报文，并从这里面读取完整的请求

        // 长服务

        while(true)
        {
            // 1. 首先读取数据，将数据从(网络中)缓冲区拿上来,然后放入数据流队列
            std::string tail;
            ssize_t n = sockfd->Recv(&tail);
            if (n <= 0)
            {
                LOG(INFO, "client %s quit or recv error\n", addr.AddrStr().c_str());
                break;
            }
            packagestreamqueue += tail;

            // 2. 从队列中分离出完整的请求，如果请求不完整，则接着循环
            std::string package = Decode(packagestreamqueue);
            if(package.empty()) continue;

            // 3. 将请求反序列化得到对应的有用的数据
            //> 需要注意的是，这里使用了 auto和工厂模式，这样一来就将IOservice和协议进行解耦了
            //  如果要使用其他的协议只需要在外部修改即可
            auto req = Factory::BuildRequestDefault();
            req->DeSerialize(package);


            // 4. 业务处理,得到结果
            auto resp = _process(req);

            // 5. 序列化结果，得到json串
            std::string respjson;
            resp->Serialize(&respjson);

            // 6. 构建完整的应答，用得到的json串
            respjson = Encode(respjson);

            std::cout << "respjson add header done: \n" << respjson << std::endl;

            // 7. 发送回去
            sockfd->Send(respjson);
        }
    }
private:
    process_t _process;
};